package com.learning.crpc.provider;

import com.alibaba.fastjson.JSONObject;
import com.learning.crpc.Application;
import com.learning.crpc.model.CrpcRequest;
import com.learning.crpc.model.CrpcResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @program: diy_rpc
 * @description: 服务提供方开放端口
 * @author: CaoYong
 * @create: 2021-06-30 10:04
 **/
@Component
@Slf4j
public class SocketProviderServer implements SmartApplicationListener, ApplicationContextAware {

    ApplicationContext applicationContext;

    /**
     * 选择需要监听Spring启动事件和关闭事件
     * @param
     * @return
     */
    @Override
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventTvpe) {
        return eventTvpe == ContextClosedEvent.class || eventTvpe == ContextStartedEvent.class || eventTvpe == ApplicationStartedEvent.class;
    }

    @Override
    public boolean supportsSourceType(Class<?> sourceType) {
        return true;
    }

    /**
     * 实现监听Spring服务启动事件，spring加载完毕后启动网络通信端口
     * @param applicationEvent
     */
    @Override
    public void onApplicationEvent(ApplicationEvent applicationEvent) {
        try {
            if (applicationEvent instanceof ApplicationStartedEvent) {
                System.out.println("spring启动了");
                ServerSocket serverSocket = new ServerSocket(8081);
                System.out.println("申请使用8081端口");
                while(true) {
                    Socket connection = serverSocket.accept();
                    byte[] request = new byte[1024];
                    connection.getInputStream().read(request);
                    System.out.println("接收到请求：" + new String(request));
//                    String response = "ok";
//                    connection.getOutputStream().write(response.getBytes());
                    String requestStr = new String(request);
                    CrpcRequest crpcRequest = JSONObject.parseObject(requestStr, CrpcRequest.class);
                    String result = callService(crpcRequest);
                    CrpcResponse response = new CrpcResponse();
                    response.setCode(200);
                    response.setContent(result);
                    String responseStr = JSONObject.toJSONString(response);
                    connection.getOutputStream().write(responseStr.getBytes());
                    connection.close();
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String callService() throws Exception{
        String className = "com.demo.sms.service.SmsService";
        String methodName = "sendMessage";
        Class[] paramterTypes = new Class[] {String.class, String.class};
        Object[] arguments = new Object[] {"111111111", "hello"};
        Class<?> serviceClass = Class.forName(className);
        Object serviceBean = applicationContext.getBean(serviceClass);
        Method method = serviceBean.getClass().getMethod(methodName, paramterTypes);
        Object invoke = method.invoke(serviceBean, arguments);
        return invoke.toString();
    }

    private String callService(CrpcRequest crpcRequest) throws Exception{
        String className = crpcRequest.getClassName();
        String methodName = crpcRequest.getMethodName();
        Class[] parameterTypes = crpcRequest.getParameterTypes();
        Object[] arguments = crpcRequest.getArguments();
        Class<?> serviceClass = Class.forName(className);
        Object serviceBean = applicationContext.getBean(serviceClass);
        Method method = serviceBean.getClass().getMethod(methodName, parameterTypes);
        Object invoke = method.invoke(serviceBean, arguments);
        return invoke.toString();
    }

    @Override
    public int getOrder() {
        return 20;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
